package util

import (
	"bufio"
	"errors"
	"fmt"
	"regexp"
	"strings"
)

var kConfMatch *regexp.Regexp = regexp.MustCompile(`K_CONF_[A-Z_0-9]+`)

func CheckAndReplace(content string, keyMap map[string]string) (string, []string, error) {
	// 1th in returns is content after replaced
	// 2nd in returns in error list of check result, same time 3th return will be error
	// extract all replaceable keys from temContent
	// condition: 1. name started with K_CONF_ ; 2. Not at start of a line; 3. not in a Line started with '#'
	if len(content) < 1 {
		return "", nil, errors.New("given content is blank")
	}

	errMsgs := make([]string, 0, 500)
	replacedContentList := make([]string, 0, 1000)
	errMark := false
	for i, eachLine := range SplitLines(content) {
		// line starts can't be replace variable
		if strings.HasPrefix(eachLine, "K_CONF_") {
			errMsgs = append(errMsgs, fmt.Sprintf("line: %d, starts with K_CONF", i))
			errMark = true
			continue
		}
		if strings.HasPrefix(eachLine, "#") {
			if errMark == false {
				// only append when check is ok so far
				replacedContentList = append(replacedContentList, eachLine)
			}
			continue
		}

		// logic:
		// find all replaceable variable in a line,
		// check each found replaceable variable in keyMap, if exists, replace the replaceable variable
		// with it's value and append into result list, if not exists, record err to errmsgs list
		findResult := kConfMatch.FindAllString(eachLine, -1)
		if findResult != nil {
			for _, eachFind := range findResult {
				if value, ok := keyMap[eachFind]; ok {
					// find in keyMap, replace eachLine with value
					// if value is blank, comment out this line
					if value == "" {
						eachLine = "#" + eachLine
					} else {
						eachLine = strings.Replace(eachLine, eachFind, value, 1)
					}
				} else {
					// not find in keyMap, record error
					errMsgs = append(errMsgs, fmt.Sprintf("replacable variable: %s not find in all key item", eachFind))
					errMark = true
				}
			}
			// only append to replace content list if not error
			if errMark == false {
				replacedContentList = append(replacedContentList, eachLine)
			}
		} else {
			// not find replaceable variables, directly append the line
			if errMark == false {
				replacedContentList = append(replacedContentList, eachLine)
			}
		}
	}

	if errMark == true {
		return "", errMsgs, errors.New("conf template checked fail")
	} else {
		return strings.Join(replacedContentList, "\n"), nil, nil
	}
}


func SplitLines(s string) []string {
	var lines []string
	sc := bufio.NewScanner(strings.NewReader(s))
	for sc.Scan() {
		lines = append(lines, sc.Text())
	}
	return lines
}
